﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

using Winz.JsonModel;

namespace Winz.FoeBot
{
    public class JsonResponseDataType
    {
        public string requestClass {get;set;}
        public string requestMethod {get;set;}
        public Type dataType {get;set;}

        public JsonResponseDataType(string requestClass, string requestMethod, Type dataType)
        {
            this.requestClass = requestClass;
            this.requestMethod = requestMethod;
            this.dataType = dataType;
        }
    }

    public class JsonParser
    {
        List<JsonResponseDataType> dataTypeList;

        public event PlayerVisitedEventHandler PlayerVisited;
        public event PlayerMotivatedEventHandler PlayerMotivated;
        public event GameStartedEventHandler GameStarted;
        public event BluePrintFoundEventHandler BluePrintFound;
        public event PlayerListRecievedEventHandler PlayerListRecieved;
        public event EventsRecievedEventHandler EventsRecieved;
        public event ResearchRecievedEventHandler ResearchRecieved;
        public event TradeOffersRecievedEventHandler TradeOffersRecieved;


        

        public JsonParser()
        {
            dataTypeList = new List<JsonResponseDataType>();
            dataTypeList.Add(new JsonResponseDataType("OtherPlayerService","visitPlayer",typeof(OtherPlayeCity) ) );
            dataTypeList.Add(new JsonResponseDataType("OtherPlayerService","polish",typeof(OtherPlayer) ) );
            dataTypeList.Add(new JsonResponseDataType("OtherPlayerService","motivate",typeof(OtherPlayer) ) );
            dataTypeList.Add(new JsonResponseDataType("StartupService", "getData", typeof(StartUp)));
            dataTypeList.Add(new JsonResponseDataType("OtherPlayerService", "getFriendsList", typeof(List<OtherPlayer>)));
            dataTypeList.Add(new JsonResponseDataType("OtherPlayerService", "getNeighborList", typeof(List<OtherPlayer>)));
            dataTypeList.Add(new JsonResponseDataType("OtherPlayerService", "getClanMemberList", typeof(List<OtherPlayer>)));
            dataTypeList.Add(new JsonResponseDataType("OtherPlayerService", "getEvents", typeof(List<Interaction>)));
            dataTypeList.Add(new JsonResponseDataType("ResearchService", "start", typeof(List<Research>)));
            dataTypeList.Add(new JsonResponseDataType("TradeService", "getTradeOffers", typeof(List<TradeOffer>)));

        }


        public virtual void OnTradeOffersRecieved(MessageEventArgs<List<TradeOffer>> e)
        {
            if (TradeOffersRecieved != null)
                TradeOffersRecieved(this, e);
        }


        public virtual void OnResearchRecieved(MessageEventArgs<List<Research>> e)
        {
            if (ResearchRecieved != null)
                ResearchRecieved(this, e);
        }

        public virtual void OnPlayerVisted(MessageEventArgs<OtherPlayeCity> e)
        {
            if (PlayerVisited != null)
                PlayerVisited(this, e);
        }

        
        public virtual void OnPlayerMotivated(MessageEventArgs<OtherPlayer> e)
        {
            if (PlayerMotivated != null)
                PlayerMotivated(this, e);
        }

        public void RaisePlayerMotivated(object o, MessageEventArgs<OtherPlayer> e)
        {
            if (PlayerMotivated != null)
                PlayerMotivated(o, e);
        }

        public virtual void OnGameStarted(MessageEventArgs<StartUp> e)
        {
            if (GameStarted != null)
                GameStarted(this, e);
        }

        public virtual void OnBluePrintFound(BluePrintFoundEventArgs e)
        {
            if (BluePrintFound != null)
                BluePrintFound(this, e);
        }
        
        public virtual void OnPlayerListRecieved(MessageEventArgs<List<OtherPlayer>> e)
        {
            if (PlayerListRecieved != null)
                PlayerListRecieved(this, e);
        }

        public virtual void OnEventsRecieved(MessageEventArgs<List<Interaction>> e)
        {
            if (EventsRecieved != null)
                EventsRecieved(this, e);
        }


        public void parseFile(object source, FileSystemEventArgs efs)
        {
            string file = efs.FullPath;
            string json;
            using (StreamReader stream = File.OpenText(file))
            {
                json = File.OpenText(file).ReadToEnd();
            }
            parse(json);
        }

        public void parse(string json)
        {

            List<RootObject> roots = new List<RootObject>();
            RootObject rootObject = null;

            try
            {
                roots = JsonConvert.DeserializeObject<List<RootObject>>(json);
                if (roots == null)
                    return;
            }
            catch(Exception e) {  
                return;  }

            foreach (JsonResponseDataType dt in dataTypeList)
            {
                if (roots.Select(r => new { r.requestClass, r.requestMethod }).Contains(new { dt.requestClass, dt.requestMethod }))
                {
                        if (dt.dataType == typeof(OtherPlayeCity))
                        {
                            rootObject = roots
                                        .Where(r => { return (r.requestClass == dt.requestClass) && (r.requestMethod == r.requestMethod); })
                                        .FirstOrDefault();
                            OnPlayerVisted(new MessageEventArgs<OtherPlayeCity>(
                                ((JObject)rootObject.responseData).ToObject<OtherPlayeCity>()
                                ));
                        }


                        if (dt.requestClass == "OtherPlayerService" && (dt.requestMethod == "polish" || dt.requestMethod == "motivate"))
                        {
                            rootObject = roots
                                        .Where(r => { return (r.requestClass == dt.requestClass) && (r.requestMethod == "updatePlayer"); })
                                        .FirstOrDefault();
                            List<OtherPlayer> l = ((JArray)rootObject.responseData).ToObject<List<OtherPlayer>>();

                            string _class = "BlueprintService";
                            string _method = "getUpdates";


                            if (roots.Count(r => { return (r.requestClass == _class) && (r.requestMethod == _method); }) > 0)
                            {
                                rootObject = roots
                                        .Where(r => { return (r.requestClass == _class) && (r.requestMethod == _method); })
                                        .FirstOrDefault();
                                GreatBuildingBlueprintFound gbFound = ((JObject)rootObject.responseData).ToObject<GreatBuildingBlueprintFound>();
                                OnBluePrintFound(new BluePrintFoundEventArgs(l.FirstOrDefault(), gbFound));
                            }
                            else
                            {
                                PlayerMotivated(this, new MessageEventArgs<OtherPlayer>(
                                    l.FirstOrDefault())
                                    );
                            }
                        }

                        if (dt.dataType == typeof(StartUp))
                        {
                            rootObject = roots
                                        .Where(r => { return (r.requestClass == dt.requestClass) && (r.requestMethod == r.requestMethod); })
                                        .FirstOrDefault();
                            GameStarted(this, new MessageEventArgs<StartUp>(
                            ((JObject)rootObject.responseData).ToObject<StartUp>()
                            ));
                        }


                        if (dt.dataType == typeof(List<OtherPlayer>))
                        {
                            rootObject = roots
                                        .Where(r => { return (r.requestClass == dt.requestClass) && (r.requestMethod == r.requestMethod); })
                                        .FirstOrDefault();
                            OnPlayerListRecieved(new MessageEventArgs<List<OtherPlayer>>(
                            ((JArray)rootObject.responseData).ToObject<List<OtherPlayer>>()
                            ));
                        }



                        if (dt.dataType == typeof(List<Interaction>))
                        {
                            rootObject = roots
                                        .Where(r => { return (r.requestClass == dt.requestClass) && (r.requestMethod == r.requestMethod); })
                                        .FirstOrDefault();
                            JArray respData = (JArray)rootObject.responseData;
                            JArray list = (JArray)respData[0];
                            List<Interaction> l = list.ToObject<List<Interaction>>();
                            OnEventsRecieved(new MessageEventArgs<List<Interaction>>(l) );
                        }

                        if (dt.dataType == typeof(List<Research>))
                        {
                            rootObject = roots
                                        .Where(r => { return (r.requestClass == dt.requestClass) && (r.requestMethod == r.requestMethod); })
                                        .FirstOrDefault();
                            JArray respData = (JArray)rootObject.responseData;
                            JArray list = (JArray)respData;
                            List<Research> l = list.ToObject<List<Research>>();
                            OnResearchRecieved(new MessageEventArgs<List<Research>>(l));
                        }

                        if (dt.dataType == typeof(List<TradeOffer>))
                        {
                            rootObject = roots
                                        .Where(r => { return (r.requestClass == dt.requestClass) && (r.requestMethod == r.requestMethod); })
                                        .FirstOrDefault();
                            JArray respData = (JArray)rootObject.responseData;
                            JArray list = (JArray)respData;

                            try
                            {
                                List<TradeOffer> l = list.ToObject<List<TradeOffer>>();
                                OnTradeOffersRecieved(new MessageEventArgs<List<TradeOffer>>(l));
                            }
                            catch (Exception e)
                            {
                            }
                        }


                }
            }
            }


        




        public static T parse<T>(string file, string requestMethod = "", string requestClass = "")
        {
            T res = default(T);
            List<RootObject> roots = new List<RootObject>();
            
            string json = File.OpenText(file).ReadToEnd();
            
            RootObject rootObject = null;

            try
            {
                roots = JsonConvert.DeserializeObject<List<RootObject>>(json);
            } catch (Exception e) {
                return default(T);
            }
            try
            {
//                roots.Select(r => new { r.requestClass, r.requestMethod }).Contains(new { r.requestClass, requestMethod });
                rootObject = (from root in roots
                              where (root.requestMethod == requestMethod || requestMethod == null)
                                      && (root.requestClass == requestClass || requestClass == null)
                              select root).FirstOrDefault();
            } catch (Exception e) { return default(T);}
            if (rootObject == null) return default(T);

            try
            {
                res = ((JObject)rootObject.responseData).ToObject<T>();
            }
            catch (Exception e) {
                return res;
            }

            
            return res;
        }








    }
}
